﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using UnityEngine;
using UnityEngine.Networking;

public class NetworkTransmitter : NetworkBehaviour
{
    public Dictionary<int, TransmissionData> clientTransmissionData = new Dictionary<int, TransmissionData>();
    private static int defaultBufferSize = 0x400;
    private static int kRpcRpcPrepareToReceiveBytes = 0x68443131;
    private static int kRpcRpcReceiveBytes;
    private static readonly string LOG_PREFIX = ("[" + typeof(NetworkTransmitter).Name + "]: ");
    public const int RELIABLE_SEQUENCED_CHANNEL = 0;
    private List<int> serverTransmissionIds = new List<int>();

    public event Action<int, byte[]> OnDataComepletelySent;

    public event Action<int, byte[]> OnDataCompletelyReceived;

    public event Action<int, byte[]> OnDataFragmentReceived;

    public event Action<int, byte[]> OnDataFragmentSent;

    static NetworkTransmitter()
    {
        NetworkBehaviour.RegisterRpcDelegate(typeof(NetworkTransmitter), kRpcRpcPrepareToReceiveBytes, new NetworkBehaviour.CmdDelegate(NetworkTransmitter.InvokeRpcRpcPrepareToReceiveBytes));
        kRpcRpcReceiveBytes = 0x3bf98881;
        NetworkBehaviour.RegisterRpcDelegate(typeof(NetworkTransmitter), kRpcRpcReceiveBytes, new NetworkBehaviour.CmdDelegate(NetworkTransmitter.InvokeRpcRpcReceiveBytes));
        NetworkCRC.RegisterBehaviour("NetworkTransmitter", 0);
    }

    public void CallRpcPrepareToReceiveBytes(int transmissionId, int expectedSize)
    {
        if (!NetworkServer.active)
        {
            UnityEngine.Debug.LogError("RPC Function RpcPrepareToReceiveBytes called on client.");
        }
        else
        {
            NetworkWriter writer = new NetworkWriter();
            writer.Write((short) 0);
            writer.Write((short) ((ushort) 2));
            writer.WritePackedUInt32((uint) kRpcRpcPrepareToReceiveBytes);
            writer.Write(base.GetComponent<NetworkIdentity>().netId);
            writer.WritePackedUInt32((uint) transmissionId);
            writer.WritePackedUInt32((uint) expectedSize);
            this.SendRPCInternal(writer, 0, "RpcPrepareToReceiveBytes");
        }
    }

    public void CallRpcReceiveBytes(int transmissionId, byte[] recBuffer)
    {
        if (!NetworkServer.active)
        {
            UnityEngine.Debug.LogError("RPC Function RpcReceiveBytes called on client.");
        }
        else
        {
            NetworkWriter writer = new NetworkWriter();
            writer.Write((short) 0);
            writer.Write((short) ((ushort) 2));
            writer.WritePackedUInt32((uint) kRpcRpcReceiveBytes);
            writer.Write(base.GetComponent<NetworkIdentity>().netId);
            writer.WritePackedUInt32((uint) transmissionId);
            writer.WriteBytesFull(recBuffer);
            this.SendRPCInternal(writer, 0, "RpcReceiveBytes");
        }
    }

    protected static void InvokeRpcRpcPrepareToReceiveBytes(NetworkBehaviour obj, NetworkReader reader)
    {
        if (!NetworkClient.active)
        {
            UnityEngine.Debug.LogError("RPC RpcPrepareToReceiveBytes called on server.");
        }
        else
        {
            ((NetworkTransmitter) obj).RpcPrepareToReceiveBytes((int) reader.ReadPackedUInt32(), (int) reader.ReadPackedUInt32());
        }
    }

    protected static void InvokeRpcRpcReceiveBytes(NetworkBehaviour obj, NetworkReader reader)
    {
        if (!NetworkClient.active)
        {
            UnityEngine.Debug.LogError("RPC RpcReceiveBytes called on server.");
        }
        else
        {
            ((NetworkTransmitter) obj).RpcReceiveBytes((int) reader.ReadPackedUInt32(), reader.ReadBytesAndSize());
        }
    }

    public override void OnDeserialize(NetworkReader reader, bool initialState)
    {
    }

    public override bool OnSerialize(NetworkWriter writer, bool forceAll)
    {
        bool flag;
        return flag;
    }

    [ClientRpc]
    private void RpcPrepareToReceiveBytes(int transmissionId, int expectedSize)
    {
        if (!this.clientTransmissionData.ContainsKey(transmissionId))
        {
            TransmissionData data = new TransmissionData(new byte[expectedSize]);
            this.clientTransmissionData.Add(transmissionId, data);
        }
    }

    [ClientRpc(channel=0)]
    private void RpcReceiveBytes(int transmissionId, byte[] recBuffer)
    {
        if (this.clientTransmissionData.ContainsKey(transmissionId))
        {
            TransmissionData data = this.clientTransmissionData[transmissionId];
            Array.Copy(recBuffer, 0, data.data, data.curDataIndex, recBuffer.Length);
            data.curDataIndex += recBuffer.Length;
            if (this.OnDataFragmentReceived != null)
            {
                this.OnDataFragmentReceived(transmissionId, recBuffer);
            }
            if (data.curDataIndex >= (data.data.Length - 1))
            {
                UnityEngine.Debug.Log(LOG_PREFIX + "Completely Received Data at transmissionId=" + transmissionId);
                this.clientTransmissionData.Remove(transmissionId);
                if (this.OnDataCompletelyReceived != null)
                {
                    this.OnDataCompletelyReceived(transmissionId, data.data);
                }
            }
        }
    }

    [Server]
    public void SendBytesToClients(int transmissionId, byte[] data)
    {
        if (!NetworkServer.active)
        {
            UnityEngine.Debug.LogWarning("[Server] function 'System.Void NetworkTransmitter::SendBytesToClients(System.Int32,System.Byte[])' called on client");
        }
        else
        {
            base.StartCoroutine(this.SendBytesToClientsRoutine(transmissionId, data));
        }
    }

    [DebuggerHidden, Server]
    public IEnumerator SendBytesToClientsRoutine(int transmissionId, byte[] data)
    {
        if (!NetworkServer.active)
        {
            UnityEngine.Debug.LogWarning("[Server] function 'System.Collections.IEnumerator NetworkTransmitter::SendBytesToClientsRoutine(System.Int32,System.Byte[])' called on client");
            return new IEnumerator();
        }
        return new <SendBytesToClientsRoutine>c__IteratorB { transmissionId = transmissionId, data = data, <$>transmissionId = transmissionId, <$>data = data, <>f__this = this };
    }

    private void UNetVersion()
    {
    }

    [CompilerGenerated]
    private sealed class <SendBytesToClientsRoutine>c__IteratorB : IDisposable, IEnumerator, IEnumerator<object>
    {
        internal object $current;
        internal int $PC;
        internal byte[] <$>data;
        internal int <$>transmissionId;
        internal NetworkTransmitter <>f__this;
        internal byte[] <buffer>__3;
        internal int <bufferSize>__1;
        internal NetworkTransmitter.TransmissionData <dataToTransmit>__0;
        internal int <remaining>__2;
        internal byte[] data;
        internal int transmissionId;

        [DebuggerHidden]
        public void Dispose()
        {
            this.$PC = -1;
        }

        public bool MoveNext()
        {
            uint num = (uint) this.$PC;
            this.$PC = -1;
            switch (num)
            {
                case 0:
                    UnityEngine.Debug.Log(string.Concat(new object[] { NetworkTransmitter.LOG_PREFIX, "SendBytesToClients processId=", this.transmissionId, " | datasize=", this.data.Length }));
                    this.<>f__this.CallRpcPrepareToReceiveBytes(this.transmissionId, this.data.Length);
                    this.$current = null;
                    this.$PC = 1;
                    goto Label_0221;

                case 1:
                    this.<>f__this.serverTransmissionIds.Add(this.transmissionId);
                    this.<dataToTransmit>__0 = new NetworkTransmitter.TransmissionData(this.data);
                    this.<bufferSize>__1 = NetworkTransmitter.defaultBufferSize;
                    break;

                case 2:
                    if (this.<>f__this.OnDataFragmentSent != null)
                    {
                        this.<>f__this.OnDataFragmentSent(this.transmissionId, this.<buffer>__3);
                    }
                    break;

                default:
                    goto Label_021F;
            }
            if (this.<dataToTransmit>__0.curDataIndex < (this.<dataToTransmit>__0.data.Length - 1))
            {
                this.<remaining>__2 = this.<dataToTransmit>__0.data.Length - this.<dataToTransmit>__0.curDataIndex;
                if (this.<remaining>__2 < this.<bufferSize>__1)
                {
                    this.<bufferSize>__1 = this.<remaining>__2;
                }
                this.<buffer>__3 = new byte[this.<bufferSize>__1];
                Array.Copy(this.<dataToTransmit>__0.data, this.<dataToTransmit>__0.curDataIndex, this.<buffer>__3, 0, this.<bufferSize>__1);
                this.<>f__this.CallRpcReceiveBytes(this.transmissionId, this.<buffer>__3);
                this.<dataToTransmit>__0.curDataIndex += this.<bufferSize>__1;
                this.$current = null;
                this.$PC = 2;
                goto Label_0221;
            }
            this.<>f__this.serverTransmissionIds.Remove(this.transmissionId);
            if (this.<>f__this.OnDataComepletelySent != null)
            {
                this.<>f__this.OnDataComepletelySent(this.transmissionId, this.<dataToTransmit>__0.data);
            }
            this.$PC = -1;
        Label_021F:
            return false;
        Label_0221:
            return true;
        }

        [DebuggerHidden]
        public void Reset()
        {
            throw new NotSupportedException();
        }

        object IEnumerator<object>.Current
        {
            [DebuggerHidden]
            get
            {
                return this.$current;
            }
        }

        object IEnumerator.Current
        {
            [DebuggerHidden]
            get
            {
                return this.$current;
            }
        }
    }

    public class TransmissionData
    {
        public int curDataIndex = 0;
        public byte[] data;

        public TransmissionData(byte[] _data)
        {
            this.data = _data;
        }
    }
}

